package http.nio.thread;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class SocketChannelThread implements Runnable{
    private SocketChannel socketChannel;
    private static final String targetAddress = "192.168.13.204";
    private static final int targetPort = 80;
    private static final int bufferSize = 65535;

    public SocketChannelThread(SocketChannel socketChannel){
        this.socketChannel = socketChannel;
    }

    @Override
    public void run(){
        SocketChannel targetSocketChannel = null;
        try {
            Selector selector = Selector.open();

            socketChannel.configureBlocking(false);

            targetSocketChannel = SocketChannel.open();
            InetSocketAddress targetSocketAddress = new InetSocketAddress(targetAddress, targetPort);
            targetSocketChannel.connect(targetSocketAddress);
            targetSocketChannel.configureBlocking(false);

            ByteBuffer buffer = ByteBuffer.allocate(bufferSize);

            socketChannel.register(selector, SelectionKey.OP_READ, targetSocketChannel);
            targetSocketChannel.register(selector, SelectionKey.OP_READ, socketChannel);


            Iterator<SelectionKey> readyKeys = null;
            SelectionKey readyKey = null;
            while(targetSocketChannel.isConnected()){
                selector.select();
                readyKeys = selector.selectedKeys().iterator();
                while(readyKeys.hasNext()){
                    readyKey = readyKeys.next();
                    readyKeys.remove();

                    if(readyKey.isReadable()){
                        SocketChannel sChannel = (SocketChannel)readyKey.channel();
                        SocketChannel tChannel = (SocketChannel)readyKey.attachment();
                        int byteRead = 0;
                        if((byteRead = sChannel.read(buffer)) != -1){
                            //由于处于非阻塞模式下，read方法很可能读了个寂寞，如果读取字节数为0就返回
                            if(byteRead != 0){
                                buffer.flip();
                                //因为处于非阻塞模式下，所以write方法有可能没写完数据就返回了，这里根据buffer的hasRemaining方法判断数据是否写完，没写完就一直写
                                while(buffer.hasRemaining()){
                                    tChannel.write(buffer);
                                }
                                buffer.clear();
                            }
                        }else{
                            System.out.println("Socket Channel Return -1, Close Connnection");
                            readyKey.cancel();
                            sChannel.close();
                            tChannel.close();
                        }
                    }
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
